package com.kalvan.web.servlet.interceptor;

import com.alibaba.fastjson.JSONObject;
import com.kalvan.core.http.HttpUrlUtils;
import com.kalvan.log.logback.layout.converter.ExtJsonConverter;
import com.kalvan.log.logback.layout.converter.LogTraceIdConverter;
import com.kalvan.web.utils.RequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.skywalking.apm.toolkit.trace.TraceContext;
import org.springframework.core.NamedThreadLocal;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;

/**
 * 进行接口耗时、接口请求频率统计限制等统计和拦截
 *
 * @author chenliang
 * @version 2018年11月8日
 * @see CallInterfaceInterceptor
 */
@Slf4j
public class CallInterfaceInterceptor extends HandlerInterceptorAdapter {

    public static final ThreadLocal<Map> callContext = new NamedThreadLocal<>("callContext");
    static final String USER_AGENT = "user-agent";
    static final String X_USERNAME = "x_username";
    static final String X_USER = "x_user";
    static final String X_START_TIME = "x_startTime";
    static final String NULL_SWAGGER = "null/swagger-resources/configuration/ui";
    static final String IGNORED_TRACE = "Ignored_Trace";

    /**
     * 设置请求时间
     *
     * @param startTime startTime
     */
    public static void setStartTime(long startTime) {
        callContext.get().put(X_START_TIME, startTime);
    }
    public static long getStartTime() {
       return  (long)callContext.get().get(X_START_TIME);
    }
    /**
     * 设置登录账号
     *
     * @param userName userName
     */
    public static void setUserName(String userName) {
        callContext.get().put(X_USERNAME, userName);
    }
    public static String getUserName() {
        return String.valueOf(callContext.get().get(X_USERNAME));
    }
    /**
     * 设置登录账号
     *
     * @param userInfo userInfo
     */
    public static void setUserInfo(Object userInfo) {
        callContext.get().put(X_USER, userInfo);
    }
    public static Object getUserInfo() {
        return callContext.get().get(X_USER);
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        //初始化context
        callContext.set(new HashMap());
        //设置调用时间
        setStartTime(System.currentTimeMillis());
        //设置日志戳
        LogTraceIdConverter.resetLogTraceId();
        String logTraceId = TraceContext.traceId();
        if (StringUtils.isNotBlank(logTraceId) && !IGNORED_TRACE.equals(logTraceId)) {
            //使用SkyWalking链路日志戳
            LogTraceIdConverter.setLogTraceId(logTraceId);
        }
//        else if (StringUtils.isNotBlank(request.getHeader(FeignAddHeaderRequestInterceptor.X_LOG_TRACE_ID))) {
//            //使用header请求传递的链路日志戳
//            LogTraceIdConverter.setLogTraceId(request.getHeader(FeignAddHeaderRequestInterceptor.X_LOG_TRACE_ID));
//        }
        String ip = RequestUtils.getIpAddr(request);
        String uri = request.getRequestURI();
        if (uri.contains(NULL_SWAGGER)) {
            //去掉swagger非法的请求
            return false;
        }
        String domain = RequestUtils.getDomain(request);
        if (HttpUrlUtils.isUrl(domain)) {
            log.info("请求地址:{}, ip:{} domain:{}", uri, ip, domain);
        } else {
            log.info("请求地址:{}, ip:{}", uri, ip);
        }
        log.debug("UserAgent:{}", request.getHeader(USER_AGENT));
        log.debug("参数:{}", JSONObject.toJSONString(request.getParameterMap()));
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        Long start = getStartTime();
        super.afterCompletion(request, response, handler, ex);
        Long end = System.currentTimeMillis();
        //注入ext日志域统一解析
        JSONObject object = new JSONObject();
        object.put("request_service", request.getRequestURI());
        object.put("response_time", end - start);
        ExtJsonConverter.setExtJson(object.toJSONString());
        log.info("");
        ExtJsonConverter.resetExtJson();

        //清理ThreadLocal
        callContext.remove();
        LogTraceIdConverter.resetLogTraceId();
    }
}
